#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
#include <QDate>
#include <QThread>
#include <QDebug>
#include "logworker.h"

LogWorker::LogWorker(QObject *parent) : QObject(parent)
{
    m_maxLineCount =100* 10000;  //默认最大存储100万行
    m_maxSize = 150*1048576;  //默认最大存储150mb
    m_curWriteLineCount = 0;
    m_curWriteSize = 0;
    m_file=NULL;
}

QString LogWorker::header()
{
    return m_header;
}

void LogWorker::setHeader(const QString &header)
{
    m_header=header;
}

QString LogWorker::fileDir()
{
    return m_fileDir;
}

void LogWorker::setFileDir(const QString &fileDir)
{
    m_fileDir=fileDir;
}

QString LogWorker::fileName()
{
    return m_fileName;
}

void LogWorker::setFileName(const QString &fileName)
{
    m_fileName=fileName;
}


/*
    返回日志文件的备份目录。默认与日志文件目录相同。
*/
QString LogWorker::backupDir()
{
    if(m_backupDir==""){
        return m_fileDir;
    }

    return m_backupDir;
}

/*
    设置日志文件的备份目录
*/
void LogWorker::setBackupDir(const QString &dir)
{
    m_backupDir = dir;
}

/*
    返回日志文件最大允许行数。默认为10000行。
*/
int LogWorker::maxLineCount()
{
    return m_maxLineCount;
}

/*
    设置日志文件最多允许的行数，超过此行数将对原文件
    进行备份，同时新建一个文件。

    注意：行数实际上是指日志写入次数，本对象认为每次调用
    writeLog()就算写入一行日志。
*/
void LogWorker::setMaxLineCount(int maxLineCount)
{
    if(maxLineCount>0){
        m_maxLineCount = maxLineCount;
    }
}

/*
    返回日志文件最大允许占用。默认为3mb
*/
int LogWorker::maxSize()
{
    return m_maxSize/1024;
}

/*
    设置日志文件最大磁盘占用（单位为mb)，日志文件超过此
    大小则将对原文件进行备份，同时新建一个文件。
*/
void LogWorker::setMaxSize(int maxSizeMb)
{
    if(maxSizeMb>0){
        m_maxSize = maxSizeMb*1048576;
    }
}

void LogWorker::open()
{
    //初始化备份记录变量
    m_curWriteLineCount = 0;
    m_curWriteSize = 0;
    m_beginDateTime = QDateTime::currentDateTime();

    //如果日志文件已经存在，则先执行一次备份
    m_file=new QFile(this);
    m_file->setFileName(m_fileDir+"/"+m_fileName+".log");
    if(m_file->exists()){
        backup();
    }

    //创建日志存储目录
    QDir dir(m_fileDir);
    if(!dir.exists()){
        if(!dir.mkpath(dir.absolutePath())){
            qWarning()<<__FUNCTION__<<"无法创建存储路径："<<dir.absolutePath();
            return ;
        }
    }

    //创建并初始化日志文件
    if(m_file->open(QFile::WriteOnly | QFile::Append)){
        //写入文件头
        QString text = m_header+"\n";
        int size = m_file->write(text.toUtf8());
        m_file->flush(); //不关闭文件写，必须flush，否则日志只有关闭时才会输出到文件中
        m_curWriteSize+=size;
        m_curWriteLineCount+=1;
    }else{
        qWarning()<<__FUNCTION__<<"无法打开日志文件："<<m_file->fileName();
    }
}

void LogWorker::close()
{
    if(m_file){
        m_file->close();
    }
}

/*
    写日志文件。写入的日志格式为：

    [日期] [日志等级] 日志信息

    level：日志等级。
    text：需要写入文件的日志信息。
*/
void LogWorker::write(const QString &text)
{
    //先检查备份
    if(isNeedBackup()){
        backup();
        open();
    }

    //再写入日志
    if(m_file->isOpen()){
        int size = m_file->write(text.toUtf8());
        m_file->flush(); //不关闭文件写，必须flush，否则日志只有关闭时才会输出到文件中
        m_curWriteLineCount+=1;
        m_curWriteSize += size;

#ifdef QT_DEBUG
        qDebug()<<text;
#endif

    }else{
        qWarning()<<__FUNCTION__<<"无法写日志文件："<<m_file->fileName()<<"文件未打开";
    }
}


/*
    检查是否需要对当前日志文件进行备份。
*/
bool LogWorker::isNeedBackup()
{
    if(!m_file->exists()){
        return false;
    }

    bool needBackup = false;
    if(!m_file->isOpen()){
        //如果当前文件已存在但未打开，则需要备份文件。例如重启应用程序时。
        needBackup = true;
    }else{
        bool isCrossDay = false;
        QDateTime curDateTime = QDateTime::currentDateTime();
        if(curDateTime.date().year()> m_beginDateTime.date().year() ||
            curDateTime.date().month() > m_beginDateTime.date().month() ||
            curDateTime.date().day() > m_beginDateTime.date().day())
        {
            isCrossDay = true;
        }

        if(isCrossDay){
            //如果当前时间相较首次打开文件的时间，出现了跨年/跨天/跨月，则需备份文件。
            needBackup = true;
        }else if(m_curWriteSize >= m_maxSize){
            //如果当前向文件写入的数据量超过最大允许的数据量，则需备份文件
            needBackup = true;
        }else if(m_curWriteLineCount >= m_maxLineCount){
            //如果当前向文件写入的行数超过最大允许的行数，则需备份文件
            needBackup = true;
        }
    }

    return needBackup;
}

/*
    对当前日志文件进行备份。

    注意：如果当前日志文件已被打开，则其会被关闭。备份后应手动调用
    open()再将其打开。
*/
void LogWorker::backup()
{  
    QFileInfo fileInfo(m_fileDir+"/"+m_fileName+".log");
    if(!fileInfo.exists()){
        return;
    }

    //创建备份目录，目录名为文件最后一次的修改日期
    QString backPath;
    QDateTime fileDate= fileInfo.created();
    backPath =backupDir()+"/"+fileDate.toString("yyyy-MM-dd");
    QDir backDir(backPath);
    if(!backDir.exists()){
        if(!backDir.mkpath(backDir.absolutePath())){
            qWarning()<<__FUNCTION__<<"无法创建备份文件：备份目录创建失败";
            return;
        }
    }

    //计算备份文件名（时间戳加上原名）
    QString backFileName = QString("%1.%2.%3")
                            .arg(fileInfo.baseName())
                            .arg(fileDate.toMSecsSinceEpoch())
                            .arg(fileInfo.suffix());

    //转移文件到备份目录
    if(m_file){
        QDateTime curDateTime = QDateTime::currentDateTime();
        QString curDateTimeStr = curDateTime.toString("yyyy-MM-dd HH:mm:ss.zzz");
        if(m_file->isOpen()){
            QString log = QString("\n[%1] -------------日志记录到达限制，已备份！----------------")
                    .arg(curDateTimeStr);
            m_file->write(log.toUtf8());
            m_file->close();
        }else{
            if(m_file->open(QFile::WriteOnly | QFile::Append)){
                QString log = QString("\n[%1] -------------旧日志文件，已备份！----------------")
                        .arg(curDateTimeStr);
                m_file->write(log.toUtf8());
                m_file->close();
            }
        }
        QFile::rename(fileInfo.absoluteFilePath(),backPath+"/"+backFileName);
    }else{
        QFile::rename(fileInfo.absoluteFilePath(),backPath+"/"+backFileName);
    }
}

